﻿/*
 *       This file is part of VFC.
 *
 *        VFC is free software: you can redistribute it and/or modify
 *        it under the terms of the GNU General Public License as published by
 *        the Free Software Foundation, either version 3 of the License, or
 *        (at your option) any later version.
 *
 *        VFC is distributed in the hope that it will be useful,
 *        but WITHOUT ANY WARRANTY; without even the implied warranty of
 *        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *        GNU General Public License for more details.
 *
 *        You should have received a copy of the GNU General Public License
 *        along with VFC.  If not, see <http://www.gnu.org/licenses/>.
 */


using System;
using System.Collections.Generic;
//using System.Linq;
using System.Text;
using System.IO;

namespace VFC.Emu
{
    class RomReader
    {
        byte[] rom;
        string RomPath;
        StringBuilder sb = new StringBuilder();
        StringBuilder sb2 = new StringBuilder();
        int iCtr, iCtr2;

        //Returning RomBank using a function is a BIG NO. Massive slowdown...
        public byte[,] RomBank = new byte[16, 16384];
        public byte[,] VRomBank = new byte[16, 8192];

        public RomReader(string path)
        {
            RomPath = path;
            try
            {
                FileStream fs = File.Open(path, FileMode.Open);
                BinaryReader br = new BinaryReader(fs);
                br.BaseStream.Seek(0, SeekOrigin.Begin);
                rom = new byte[Convert.ToInt32(fs.Length)];
                rom = br.ReadBytes(Convert.ToInt32(fs.Length));
                fs.Dispose();
                br.BaseStream.Dispose();
                br.Close();
                fs.Close();
            }
            catch (Exception err)
            {
                Console.WriteLine("ERROR: " + err.Message);
            }
        }

        public string RomFileName()
        {
            string[] tmp;
            string rTmp = "";

            try
            {
                tmp = RomPath.Split('\\');
                rTmp = tmp[tmp.Length - 1];
            }
            catch (Exception err)
            {
                Console.WriteLine("ERROR: " + err.Message);
            }
            return rTmp;
        }

        public bool IsNes()
        {
            /* 0x4e = N
             * 0x45 = E
             * 0x53 = S
             */
            if (rom[0] == 0x4e && rom[1] == 0x45 && rom[2] == 0x53)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public int Count16KbRomBank()
        {
            return rom[4];
        }

        public int Count8KbVRomBank()
        {
            return rom[5];
        }

        public int MapperNumber()
        {
            int h, l;
            h = rom[7] >> 4;
            l = rom[6] >> 4;
            return ((h << 4) + l);
        }

        public string Mirroring()
        {
            if ((rom[6] & 0x01) == 1)
            {
                return "VERTICAL";
            }
            else
            {
                return "HORIZONTAL";
            }
        }

        public bool Is512ByteTrainerPresent()
        {
            if ((rom[6] & 0x04) == 1)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public bool IsBatteryBacked()
        {
            if ((rom[6] & 0x02) == 1)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public bool Is4ScreenLayout()
        {
            if ((rom[6] & 0x08) == 1)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public bool VsSystem()
        {
            if ((rom[7] & 0x01) == 1)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public string Region()
        {
            if ((rom[9] & 0x01) == 1)
            {
                return "PAL";
            }
            else
            {
                return "NTSC";
            }
        }

        public int Count8KbRamBank()
        {
            return rom[8];
        }

        public void Get16KbRomBank()
        {
            const int _16Kb = 16383; //16kb...
            int _16KbCount = (int)rom[4];
            int ctr, start, end, rCtr=0, iCtr=0;

            try
            {
                if (this.Is512ByteTrainerPresent())
                {
                    start = 16 + 512;
                    end = start + _16Kb;
                }
                else
                {
                    start = 16;
                    end = start + _16Kb;
                }

                for (iCtr = 0; iCtr <= _16KbCount - 1; iCtr++)
                {
                    for (ctr = start; ctr <= end; ctr++)
                    {
                        RomBank[iCtr, rCtr] = rom[ctr];
                        rCtr++;
                    }
                    start += _16Kb;
                    end += _16Kb;
                    rCtr = 0;
                }
            }
            catch(Exception err)
            {
                Console.WriteLine("ERROR: " + err.Message);
            }
            ctr = 0;
            rCtr = 0;
            start = 0;
            end = 0;
        }

        public byte[,] Get8KbVRomBank()
        {
            const int _8Kb = 8192; //8Kb...
            const int _16Kb = 16384; //16Kb...
            int _16KbCount = (int)rom[4];
            int _8KbCount = (int)rom[5];
            
            int ctr, start, end, rCtr = 0, iCtr = 0;

            byte[,] tmp = new byte[_8KbCount, _8Kb];

            try
            {
                if (this.Is512ByteTrainerPresent())
                {
                    start = 16 + 512 + _16Kb;
                    end = start + _8Kb;
                }
                else
                {
                    start = 16 + _16Kb;
                    end = start + _8Kb;
                }

                for (iCtr = 0; iCtr <= _8KbCount - 1; iCtr++)
                {
                    for (ctr = start; ctr <= end - 1; ctr++)
                    {
                        tmp[iCtr, rCtr] = rom[ctr];
                        rCtr++;
                    }
                    start += _8Kb;
                    end += _8Kb;
                    rCtr = 0;
                }
            }
            catch (Exception err)
            {
                Console.WriteLine("ERROR: " + err.Message);
            }
            ctr = 0;
            rCtr = 0;
            start = 0;
            end = 0;
            return tmp;
        }

        public string GetRomString()
        {
            iCtr = 0;
            iCtr2 = 0;
            string hex = BitConverter.ToString(rom);
            string[] tmp_hex = hex.Split('-');
            string _tmp;

            for (int ctr = 0; ctr <= tmp_hex.Length - 1; ctr++)
            {
                if (iCtr < 16)
                {
                    if (ctr != tmp_hex.Length - 1)
                    {
                        if (iCtr2 < 7)
                        {
                            sb.Append(tmp_hex[ctr]);
                            sb.Append(" ");
                            iCtr++;
                            iCtr2++;
                        }
                        else
                        {
                            sb.Append(tmp_hex[ctr]);
                            sb.Append("    ");
                            iCtr++;
                            iCtr2 = 0;
                        }
                    }
                    else
                    {
                        sb2.AppendLine(sb.ToString());
                        sb.Length = 0;
                        iCtr = 0;
                    }
                }
                else
                {
                    sb2.AppendLine(sb.ToString());
                    sb.Length = 0;
                    iCtr = 0;
                }
            }
            _tmp = sb2.ToString();
            sb2.Length = 0;
            return _tmp;
        }
    }
}
